"use strict";

var $ = require("jquery");

require("ui/date_box/ui.time_view");

QUnit.testStart(function() {
    var markup =
        '<div id="timeView"></div>';

    $("#qunit-fixture").html(markup);
});

var TIMEVIEW_CLASS = "dx-timeview",
    TIMEVIEW_CLOCK_CLASS = "dx-timeview-clock",
    TIMEVIEW_FIELD_CLASS = "dx-timeview-field",
    TIMEVIEW_HOURARROW_CLASS = "dx-timeview-hourarrow",
    TIMEVIEW_MINUTEARROW_CLASS = "dx-timeview-minutearrow",
    TIMEVIEW_TIME_SEPARATOR_CLASS = "dx-timeview-time-separator",

    BOX_CLASS = "dx-box",
    NUMBERBOX_CLASS = "dx-numberbox";

QUnit.module("rendering");

QUnit.test("widget class should be added", function(assert) {
    var $element = $("#timeView").dxTimeView();

    assert.ok($element.hasClass(TIMEVIEW_CLASS), "class added");
});

QUnit.test("timeView should use box with right options", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        box = $element.find("." + BOX_CLASS).dxBox("instance");

    assert.equal(box.option("direction"), "col", "box has right direction");
    assert.equal(box.option("items").length, 2, "box has 2 items");
});

QUnit.test("clock should be rendered in top box section", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        box = $element.find("." + BOX_CLASS).dxBox("instance");

    assert.ok(box.itemElements().eq(0).find("." + TIMEVIEW_CLOCK_CLASS).length, "clock rendered");
});

QUnit.test("field should be rendered in bottom box section", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        box = $element.find("." + BOX_CLASS).dxBox("instance");

    assert.ok(box.itemElements().eq(1).find("." + TIMEVIEW_FIELD_CLASS).length, "clock rendered");
});


QUnit.module("clock rendering");

QUnit.test("hour arrow should be rendered", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        $clock = $element.find("." + TIMEVIEW_CLOCK_CLASS);

    assert.ok($clock.find("." + TIMEVIEW_HOURARROW_CLASS).length, "hour arrow rendered");
});

QUnit.test("minute arrow should be rendered", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        $clock = $element.find("." + TIMEVIEW_CLOCK_CLASS);

    assert.ok($clock.find("." + TIMEVIEW_MINUTEARROW_CLASS).length, "minute arrow rendered");
});

QUnit.test("clock should not render if showClock option is false", function(assert) {
    var $element = $("#timeView").dxTimeView({
            _showClock: false
        }),
        $clock = $element.find("." + TIMEVIEW_CLOCK_CLASS);

    assert.notOk($clock.length, "clock was not rendered");
});

QUnit.test("clock should be shown if showClock option was changed", function(assert) {
    var $element = $("#timeView").dxTimeView({
            _showClock: false
        }),
        instance = $element.dxTimeView("instance");

    instance.option("_showClock", true);

    var $clock = $element.find("." + TIMEVIEW_CLOCK_CLASS);

    assert.ok($clock.length, "clock was rendered");
});


var getRotation = function($element) {
    var matrix = $element.css("transform"),
        values = matrix.split('(')[1].split(')')[0].split(',');

    return Math.round(Math.atan2(values[1], values[0]) * (180 / Math.PI));
};

QUnit.test("hour arrow has right rotation", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 3, 0)
        }),
        $hourArrow = $element.find("." + TIMEVIEW_HOURARROW_CLASS);

    assert.equal(getRotation($hourArrow), 90, "arrow rotation is right");
});

QUnit.test("hour arrow has right rotation considering minutes", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 3, 30)
        }),
        $hourArrow = $element.find("." + TIMEVIEW_HOURARROW_CLASS);

    assert.equal(getRotation($hourArrow), 105, "arrow rotation is right");
});

QUnit.test("minute arrow has right rotation", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 3, 45)
        }),
        $minuteArrow = $element.find("." + TIMEVIEW_MINUTEARROW_CLASS);

    assert.equal(getRotation($minuteArrow), -90, "arrow rotation is right");
});

QUnit.test("hour arrow has right rotation after changing time option", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        instance = $element.dxTimeView("instance"),
        $hourArrow = $element.find("." + TIMEVIEW_HOURARROW_CLASS);

    instance.option("value", new Date(2014, 11, 11, 5, 0));

    assert.equal(getRotation($hourArrow), 150, "arrow rotation is right");
});

QUnit.test("minute arrow has right rotation after changing time option", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        instance = $element.dxTimeView("instance"),
        $minuteArrow = $element.find("." + TIMEVIEW_MINUTEARROW_CLASS);

    instance.option("value", new Date(2014, 11, 11, 6, 25));

    assert.equal(getRotation($minuteArrow), 150, "arrow rotation is right");
});


QUnit.module("field rendering");

QUnit.test("field should be box widget", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        box = $element.find("." + TIMEVIEW_FIELD_CLASS).dxBox("instance");

    assert.equal(box.option("direction"), "row", "rendered");
    assert.equal(box.option("align"), "center", "rendered");
    assert.equal(box.option("crossAlign"), "center", "rendered");
});

QUnit.test("field should contain hour numberbox with current hour value", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 11, 22)
        }),
        box = $element.find("." + TIMEVIEW_FIELD_CLASS).dxBox("instance");

    var hourNumberBox = box.itemElements().eq(0).find("." + NUMBERBOX_CLASS).dxNumberBox("instance");

    assert.equal(hourNumberBox.option("showSpinButtons"), true, "spin buttons enabled");
    assert.equal(hourNumberBox.option("value"), 11, "correct hour value");
});

QUnit.test("hours and minutes should be separated by time separator", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 11, 22)
        }),
        $separator = $element.find("." + TIMEVIEW_TIME_SEPARATOR_CLASS);

    assert.equal($separator.length, 1, "separator should exist");
});

QUnit.test("hour numberbox should set hours", function(assert) {
    var time = new Date(2014, 11, 11, 11, 22);

    var $element = $("#timeView").dxTimeView({
            value: time
        }),
        instance = $element.dxTimeView("instance"),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance");

    hourNumberBox.option("value", 5);

    assert.notStrictEqual(instance.option("value"), time, "date instance changed");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 5, 22).valueOf(), "hour changed");
});

QUnit.test("hour numberbox should be updated after time option change", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 11, 22)
        }),
        instance = $element.dxTimeView("instance"),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance");

    instance.option("value", new Date(2014, 11, 11, 7, 22));

    assert.equal(hourNumberBox.option("value"), 7, "hour changed");
});

QUnit.test("field should contain minute numberbox with current minute value", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 11, 22)
        }),
        box = $element.find("." + TIMEVIEW_FIELD_CLASS).dxBox("instance");

    var minuteNumberBox = box.itemElements().eq(2).find("." + NUMBERBOX_CLASS).dxNumberBox("instance");

    assert.equal(minuteNumberBox.option("showSpinButtons"), true, "spin buttons enabled");
    assert.equal(minuteNumberBox.option("value"), 22, "correct hour value");
});

QUnit.test("minute numberbox should set minutes", function(assert) {
    var time = new Date(2014, 11, 11, 11, 22);

    var $element = $("#timeView").dxTimeView({
            value: time
        }),
        instance = $element.dxTimeView("instance"),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    minuteNumberBox.option("value", 33);

    assert.notStrictEqual(instance.option("value"), time, "date instance changed");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 11, 33).valueOf(), "minute changed");
});

QUnit.test("minute numberbox should be updated after time option change", function(assert) {
    var $element = $("#timeView").dxTimeView({
            value: new Date(2014, 11, 11, 11, 22)
        }),
        instance = $element.dxTimeView("instance"),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    instance.option("value", new Date(2014, 11, 11, 11, 33));

    assert.equal(minuteNumberBox.option("value"), 33, "minute changed");
});

QUnit.test("hour numberbox should be looped", function(assert) {
    var time = new Date(2014, 11, 11, 11, 22);

    var $element = $("#timeView").dxTimeView({
            value: time
        }),
        instance = $element.dxTimeView("instance"),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance");

    hourNumberBox.option("value", 24);
    assert.equal(hourNumberBox.option("value"), 0, "numberbox updated");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 0, 22).valueOf(), "minute changed");

    hourNumberBox.option("value", -1);
    assert.equal(hourNumberBox.option("value"), 23, "numberbox updated");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 23, 22).valueOf(), "minute changed");
});

QUnit.test("minute numberbox should be looped", function(assert) {
    var time = new Date(2014, 11, 11, 11, 22);

    var $element = $("#timeView").dxTimeView({
            value: time
        }),
        instance = $element.dxTimeView("instance"),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    minuteNumberBox.option("value", 60);
    assert.equal(minuteNumberBox.option("value"), 0, "numberbox updated");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 11, 0).valueOf(), "minute changed");

    minuteNumberBox.option("value", -1);
    assert.equal(minuteNumberBox.option("value"), 59, "numberbox updated");
    assert.equal(instance.option("value").valueOf(), new Date(2014, 11, 11, 11, 59).valueOf(), "minute changed");
});

QUnit.test("hour and minute numberboxes should set minutes with null value", function(assert) {
    assert.expect(2);

    var expected;

    var $element = $("#timeView").dxTimeView({
            value: null,
            onValueChanged: function(args) {
                if(expected) {
                    assert.ok(Math.abs(args.value.valueOf() - expected.valueOf()) < 60 * 1000, "correct value");
                }
            }
        }),
        instance = $element.dxTimeView("instance"),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance"),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    expected = new Date();
    expected.setHours((expected.getHours() + 24 + 1) % 24);
    hourNumberBox.option("value", expected.getHours());

    expected = null;
    instance.option("value", null);

    expected = new Date();
    expected.setMinutes((expected.getMinutes() + 60 + 1) % 60);
    minuteNumberBox.option("value", expected.getMinutes());
});

QUnit.test("disabled state should be passed to numberboxes", function(assert) {
    var $element = $("#timeView").dxTimeView({
            disabled: true
        }),
        instance = $element.dxTimeView("instance"),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance"),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    assert.equal(hourNumberBox.option("disabled"), true, "hour numberbox disabled");
    assert.equal(minuteNumberBox.option("disabled"), true, "minute numberbox disabled");

    instance.option("disabled", false);
    assert.equal(hourNumberBox.option("disabled"), false, "hour numberbox disabled");
    assert.equal(minuteNumberBox.option("disabled"), false, "minute numberbox disabled");
});


QUnit.module("format rendering");

QUnit.test("minute numberbox should have min/max constraints", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        minuteNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(1).dxNumberBox("instance");

    assert.equal(minuteNumberBox.option("min"), -1, "min constraint set");
    assert.equal(minuteNumberBox.option("max"), 60, "max constraint set");
});

QUnit.test("hour numberbox should have min/max constraints", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        hourNumberBox = $element.find("." + NUMBERBOX_CLASS).eq(0).dxNumberBox("instance");

    assert.equal(hourNumberBox.option("min"), -1, "min constraint set");
    assert.equal(hourNumberBox.option("max"), 24, "max constraint set");
});


QUnit.module("editor support");

QUnit.test("value changed should be raised on value change", function(assert) {
    assert.expect(1);

    var time = new Date(2014, 11, 11, 11, 22);

    var $element = $("#timeView").dxTimeView({
            onValueChanged: function(args) {
                assert.equal(args.value.valueOf(), time.valueOf(), "value changed");
            }
        }),
        instance = $element.dxTimeView("instance");

    instance.option("value", time);
});


QUnit.module("aria accessibility");

QUnit.test("role for clock picture", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        $clock = $element.find(".dx-timeview-clock");

    assert.equal($clock.attr("role"), "presentation");
});

QUnit.test("label for hour and minute numberboxes", function(assert) {
    var $element = $("#timeView").dxTimeView(),
        $hour = $element.find(".dx-texteditor-input[aria-valuemax='24']"),
        $minute = $element.find(".dx-texteditor-input[aria-valuemax='60']");

    assert.equal($hour.attr("aria-label"), "hours", "hours label is correct");
    assert.equal($minute.attr("aria-label"), "minutes", "minutes label is correct");
});
